using System;
using System.Linq;

namespace Kiwi.Container.Application
{
    public class ContainerManager
    {
        private static readonly object _sync = new object();
        private static Func<IContainer> _createContainer;
        private static IFramework[] _frameworks;
        private static IContainer _rootContainer;

        public static IContainer Current
        {
            get
            {
                var container = Root;
                foreach (
                    var activator in
                        _rootContainer.Extensions.Select(ext => ext as ILocalContainerActivator).Where(a => a != null))
                {
                    var childContainer = activator.GetLocalContainer(container);
                    if (childContainer != null)
                    {
                        container = childContainer;
                    }
                }
                return container;
            }
        }

        public static IContainer Root
        {
            get
            {
                if (_rootContainer == null)
                {
                    lock (_sync)
                    {
                        if (_rootContainer == null)
                        {
                            if (_frameworks == null)
                            {
                                throw new ContainerConfigurationException(Resource.ContainerManagerIsNotConfigued);
                            }
                            _rootContainer = _createContainer();
                        }
                    }
                }
                return _rootContainer;
            }
        }

        public static void Configure(Func<IContainer> createContainer, params IFramework[] frameworks)
        {
            if (createContainer == null)
            {
                throw new ArgumentNullException("createContainer");
            }
            if (frameworks == null)
            {
                throw new ArgumentNullException("frameworks");
            }
            if (frameworks.Length == 0)
            {
                throw new ArgumentException("At least one framework must be defined.", "frameworks");
            }
            lock (_sync)
            {
                _createContainer = createContainer;
                _frameworks = frameworks;

                foreach (var framework in _frameworks)
                {
                    framework.Initialize();
                }
            }
        }
    }
}